import javax.swing.*;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;
import javax.swing.plaf.FontUIResource;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.*;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * @author lixiaodong
 */
public class MainForm {
    /*
     * git diff a10aac7...9baf397 --name-only
     */

    private static JFrame frame;

    public static void main(String[] args) {
//        List<Integer> list = new ArrayList<>(100);
//        for (int i = 0; i < 100; i++) {
//            list.add(i);
//        }
//        System.out.println("mainThread:" + Thread.currentThread().getName());
////        list.parallelStream().forEach(i -> {
////            try {
////                Thread.sleep(500);
////            } catch (InterruptedException e) {
////                e.printStackTrace();
////            }
////            System.out.println("thread:" + Thread.currentThread().getName() + ":" + i);
////        });
//        ForkJoinPool pool = new ForkJoinPool(1);
//        for (Integer i : list) {
//            pool.execute(new Runnable() {
//                @Override
//                public void run() {
//                    try {
//                        Thread.sleep(500);
//                    } catch (InterruptedException e) {
//                        e.printStackTrace();
//                    }
//                    System.out.println("thread:" + Thread.currentThread().getName() + ":" + i);
//                }
//            });
//        }
//        pool.shutdown();
//        try {
//            pool.awaitTermination(1, TimeUnit.DAYS);
//        } catch (InterruptedException e) {
//            e.printStackTrace();
//        }


        initGlobalFont(new Font("宋体", Font.PLAIN, 12));
        frame = new JFrame("GitExport");
        frame.setContentPane(new MainForm().panel1);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.pack();
        frame.setSize(500, 360);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    private JPanel panel1;
    private JTextField textSource;
    private JButton btnPatchExport;
    private JButton btnSelectPatch;
    private JTextField textProject;
    private JButton btnSelectTarget;
    private JTextField textOutput;
    private JButton btnOutput;
    private JButton btnGitExport;
    private JButton btnFileExport;

    public MainForm() {
        btnSelectPatch.addActionListener(buttonActionListener);
        btnSelectTarget.addActionListener(buttonActionListener);
        btnPatchExport.addActionListener(buttonActionListener);
        btnOutput.addActionListener(buttonActionListener);
        btnFileExport.addActionListener(buttonActionListener);
        btnGitExport.addActionListener(buttonActionListener);
        textSource.setText(Helper.getValue("source"));
        textProject.setText(Helper.getValue("project"));
        textOutput.setText(Helper.getValue("output"));
        textSource.getDocument().addDocumentListener(new MyDocumentListener("source", textSource));
        textProject.getDocument().addDocumentListener(new MyDocumentListener("project", textProject));
        textOutput.getDocument().addDocumentListener(new MyDocumentListener("output", textOutput));
    }

    private static void initGlobalFont(Font font) {
        FontUIResource fontRes = new FontUIResource(font);
        for (Enumeration<Object> keys = UIManager.getDefaults().keys();
             keys.hasMoreElements(); ) {
            Object key = keys.nextElement();
            Object value = UIManager.get(key);
            if (value instanceof FontUIResource) {
                UIManager.put(key, fontRes);
            }
        }
    }

    private static void chooseFile(int selectMode, String title, JTextField textField) {
        JFileChooser chooser = new JFileChooser();
        chooser.setMultiSelectionEnabled(false);
        chooser.setFileSelectionMode(selectMode);
        chooser.setDialogTitle(title);
        if (chooser.showOpenDialog(frame) == JFileChooser.APPROVE_OPTION) {
            File file = chooser.getSelectedFile();
            textField.setText(file.getAbsolutePath());
        }
    }

    private ActionListener buttonActionListener = new ActionListener() {
        @Override
        public void actionPerformed(ActionEvent e) {
            if (e.getSource().equals(btnSelectPatch)) {
                chooseFile(JFileChooser.FILES_ONLY, "选择Patch文件", textSource);
            }
            if (e.getSource().equals(btnSelectTarget)) {
                chooseFile(JFileChooser.DIRECTORIES_ONLY, "选择编译输出路径(target)", textProject);
            }
            if (e.getSource().equals(btnOutput)) {
                chooseFile(JFileChooser.DIRECTORIES_ONLY, "选择复制路径(output)", textOutput);
            }
            if (e.getSource().equals(btnPatchExport)) {
                startPatchExport();
            }
            if (e.getSource().equals(btnFileExport)) {
                startFileExport();
            }
            if (e.getSource().equals(btnGitExport)) {
                startGitExport();
            }
        }
    };

    static Pattern pattern = Pattern.compile("^index:\\s*(\\S+?)$", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);
    static Pattern pattern_bin = Pattern.compile("^diff --git\\s+(\\S+?)\\s+", Pattern.CASE_INSENSITIVE | Pattern.MULTILINE);

    private static final String PATH_JAVA = "src/main/java";
    private static final String PATH_RESOURCE = "src/main/resources";
    private static final String PATH_WEBAPP = "src/main/webapp";

    private void startPatchExport() {
        File f = new File(textSource.getText().trim());
        try (FileInputStream stream = new FileInputStream(f)) {
            byte[] bs = new byte[stream.available()];
            stream.read(bs);
            String s = new String(bs, 0, bs.length, "utf-8");
            List<String> list = new ArrayList<>();
            Matcher matcher = pattern.matcher(s);
            while (matcher.find()) {
                list.add(matcher.group(1));
            }
            matcher = pattern_bin.matcher(s);
            while (matcher.find()) {
                list.add(matcher.group(1));
            }

            export(list);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void startFileExport() {
        File f = new File(textSource.getText().trim());
        try (FileInputStream stream = new FileInputStream(f)) {
            byte[] bs = new byte[stream.available()];
            stream.read(bs);
            String s = new String(bs, 0, bs.length, "utf-8");
            List<String> list = new ArrayList<>();
            for (String str : s.split("\\n")) {
                if (str != null && !(str = str.trim()).equals("")) {
                    str = str.replace(File.separator, "/");
                    list.add(str);
                }
            }

            export(list);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void startGitExport() {
        String cmd = "git diff " + textSource.getText().trim() + " --name-only";
        String text = executeCommand(cmd, new File(textProject.getText().trim()));
        List<String> list = new ArrayList<>();
        for (String str : text.split("\\n")) {
            if (str != null && !(str = str.trim()).equals("")) {
                str = str.replace(File.separator, "/");
                list.add(str);
            }
        }

        export(list);
    }

    private final void export(List<String> relativePathList) {
        for (String str : relativePathList) {
            Path source;
            Path target;
            int index;
            if ((index = str.toLowerCase().indexOf(PATH_JAVA)) >= 0) {
                str = str.substring(index);
                source = Paths.get(textProject.getText().trim(), "target", "classes", str.substring(PATH_JAVA.length()).replace("/", File.separator));
                target = Paths.get(textOutput.getText().trim(), "WEB-INF", "classes", str.substring(PATH_JAVA.length()).replace("/", File.separator));
            } else if ((index = str.toLowerCase().indexOf(PATH_RESOURCE)) >= 0) {
                str = str.substring(index);
                source = Paths.get(textProject.getText().trim(), "target", "classes", str.substring(PATH_RESOURCE.length()).replace("/", File.separator));
                target = Paths.get(textOutput.getText().trim(), "WEB-INF", "classes", str.substring(PATH_RESOURCE.length()).replace("/", File.separator));
            } else if ((index = str.toLowerCase().indexOf(PATH_WEBAPP)) >= 0) {
                str = str.substring(index);
                source = Paths.get(textProject.getText().trim(), str.replace("/", File.separator));
                target = Paths.get(textOutput.getText().trim(), str.substring(PATH_WEBAPP.length()).replace("/", File.separator));
            } else {
                System.out.println("------ignore------" + str);
                continue;
            }

            copyFile(source, target);
        }
    }

    private static final void copyFile(Path source, Path target) {
        target.toFile().getParentFile().mkdirs();
        if (source.toString().toLowerCase().endsWith(".java")) {
            //source.
            String fileName = source.getFileName().toString();
            String cname = fileName.substring(0, fileName.length() - 5);
            Path t1 = source.getParent();
            Path t2 = target.getParent();
            String[] list = source.getParent().toFile().list((dir, name) -> name.indexOf(cname + "$") == 0 || name.indexOf(cname + ".class") == 0);
            if (list != null) {
                for (String s : list) {
                    System.out.println(s);
                    Path t = Paths.get(t1.toString(), s);
                    Path tt = Paths.get(t2.toString(), t.getFileName().toString());
                    System.out.println(t);
                    System.out.println(tt);
                    try {
                        Files.copy(t, tt, StandardCopyOption.REPLACE_EXISTING);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            } else {
                System.out.println("------not found------" + source.toString());
            }
        } else {
            try {
                Files.copy(source, target, StandardCopyOption.REPLACE_EXISTING);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    private static final String executeCommand(String cmd, File dir) {
        BufferedReader br = null;
        Process process = null;
        try {
            process = Runtime.getRuntime().exec(cmd, null, dir);
            br = new BufferedReader(new InputStreamReader(process.getInputStream()));
            String line;
            StringBuilder sb = new StringBuilder();
            while ((line = br.readLine()) != null) {
                sb.append(line + "\n");
            }
            return sb.toString();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            if (process != null) {
                try {
                    process.destroy();
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }
}


class MyDocumentListener implements DocumentListener {
    private String key;
    private JTextField jTextField;

    public MyDocumentListener(String key, JTextField jTextField) {
        this.key = key;
        this.jTextField = jTextField;
    }

    @Override
    public void insertUpdate(DocumentEvent e) {
        Helper.setValue(key, jTextField.getText().trim());
    }

    @Override
    public void removeUpdate(DocumentEvent e) {
        Helper.setValue(key, jTextField.getText().trim());
    }

    @Override
    public void changedUpdate(DocumentEvent e) {
        Helper.setValue(key, jTextField.getText().trim());
    }
}